package com.deng.framework.beans.factory.support;

import com.deng.framework.beans.BeansException;
import com.deng.framework.beans.factory.DisposableBean;
import com.deng.framework.beans.factory.ObjectFactory;
import com.deng.framework.beans.factory.config.SingletonBeanRegistry;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 用来存储bean的单例实例化对象的类，包含了所有与数理化对象相关的操作
 * 被AbstractBeanFactory调用
 */
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {

    /**
     * 在继承该类的FactoryBeanRegistrySupport中用到了，作用如下：
     * Internal marker for a null singleton object:
     * used as marker value for concurrent Maps (which don't support null values).
     */
    protected static final Object NULL_OBJECT = new Object();

    //一级缓存，缓存完整的实例化对象(存储bean的实例化-这里使用了Map，所以我们可以认为这个类似于单例模式)
    private Map<String,Object> singletonObjects = new ConcurrentHashMap<>();

    //二级缓存，缓存提前暴露的，但是还没有完全实例化的对象
    protected final Map<String, Object> earlySingletonObjects = new HashMap<>();

    //三级缓存，存放工厂对象
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();

    //存储自定义销毁Bean的Bean对象
    private final Map<String, DisposableBean> disposableBeans = new LinkedHashMap<>();

    //将实例注册进实例map中
    @Override
    public void registerSingleton(String beanName, Object singletonObject) {
        //加入一级缓存后就需要把二级和三级缓存中的数据删除
        singletonObjects.put(beanName,singletonObject);
        earlySingletonObjects.remove(beanName);
        singletonFactories.remove(beanName);
    }

    //将提前暴露的实例添加进第三级缓存中
    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory){
        if (!this.singletonObjects.containsKey(beanName)) {
            this.singletonFactories.put(beanName, singletonFactory);
            //这里还要删除第二级缓存中的对象。不知道为啥
            this.earlySingletonObjects.remove(beanName);
        }
    }

    //注册自定义销毁bean
    public void registerDisposableBean(String beanName, DisposableBean bean) {
        disposableBeans.put(beanName, bean);
    }

    /**
     * 三级缓存解决循环依赖的重点实现函数
     * 告诉了我们怎么获取实例的，但没说依赖类是怎么提前暴露的，所以要结合ObjectFactory的继承类才能看懂
     */
    @Override
    public Object getSingleton(String beanName) {
        Object singletonObject = singletonObjects.get(beanName);
        if(null == singletonObject){
            //一级缓存没拿到，就去二级缓存拿
            singletonObject = earlySingletonObjects.get(beanName);
            if(null == singletonObject){
                //二级缓存也没有，就去三级缓存中看，如果还没有，那就是没注册
                ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);
                if(singletonFactory != null){
                    singletonObject = singletonFactory.getObject();
                    // 把三级缓存中的代理对象中的真实对象获取出来，放入二级缓存中
                    earlySingletonObjects.put(beanName, singletonObject);
                    singletonFactories.remove(beanName);
                }
            }
        }
        return singletonObject;
    }

    //自定义销毁单例对象的实现方法
    @Override
    public void destroySingletons() {
        Set<String> keySet = this.disposableBeans.keySet();
        Object[] disposableBeanNames = keySet.toArray();

        for(int i = disposableBeanNames.length - 1; i >= 0; i--){
            Object beanName = disposableBeanNames[i];
            DisposableBean disposableBean = disposableBeans.remove(beanName);
            try {
                //类似于initBean，是用户继承了DisposableBean的类的自定义的destroy方法
                disposableBean.destroy();
            } catch (Exception e) {
                throw new BeansException("Destroy method on bean with name '" + beanName + "' threw an exception", e);
            }
        }
    }
}
